package com.example.lock;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * ReentrantLock是可重入的独占锁。 比起synchronized功能更加丰富，支持公平锁实现， 支持中断响应以及限时等待等等。
 * 可以配合一个或多个Condition条件方便的实现等待通知机制。
 * 
 * @author pingxu
 *
 * @param <E>
 */
public class MyBlockingQueue<E> {

	int size;// 阻塞队列最大容量

	ReentrantLock lock = new ReentrantLock();

	LinkedList<E> list = new LinkedList<>();// 队列底层实现

	Condition notFull = lock.newCondition();// 队列满时的等待条件
	Condition notEmpty = lock.newCondition();// 队列空时的等待条件

	public MyBlockingQueue(int size) {
		this.size = size;
	}

	public void enqueue(E e) throws InterruptedException {
		lock.lock();
		try {
			while (list.size() == size) {
//				队列已满,在notFull条件上等待
				System.out.println("队列已经满了，等待");
				notFull.await();

			}
//			入队:加入链表末尾
			list.add(e);
			System.out.println("入队：" + e);
//			通知在notEmpty条件上等待的线程
			notEmpty.signal();
		} finally {
			lock.unlock();
		}
	}

	public E dequeue() throws InterruptedException {
		E e;
		lock.lock();
		try {
			while (list.size() == 0) {
//				队列为空,在notEmpty条件上等待
				System.out.println("队列为空，等待数据出现");
				notEmpty.await();
			}
			e = list.removeFirst();// 出队:移除链表首元素
			System.out.println("出队：" + e);
			notFull.signal();// 通知在notFull条件上等待的线程
			return e;
		} finally {
			lock.unlock();
		}
	}

	public static void main(String[] args) {
		MyBlockingQueue<Integer> queue = new MyBlockingQueue<>(2);
		for (int i = 0; i < 10; i++) {
			int data = i;
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						queue.enqueue(data);
					} catch (InterruptedException e) {

					}
				}
			}).start();

		}
		for (int i = 0; i < 10; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						Integer data = queue.dequeue();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}).start();
		}
	}
}
